﻿/************************************************************************************ 
 * LightObject.cs
 * 
 * Author      : Hristo Hristov
 * Datum       : 26.05.2011
 * Revision    : 10
 *************************************************************************************/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using BEPUphysics.Paths;
using NOVA.Graphics;
using NOVA.Utilities;

namespace NOVA.Scenery
{
    /// <summary>
    /// Creates a light object for scene.
    /// </summary>
    public class LightObject : ITransformable
    {
        #region Members

        /// <summary>
        /// "Theoretical" bounding box for this object
        /// </summary>
        BoundingBox m_boundingBox;

        Vector3 m_position;
        Quaternion m_rotation;
        
        string m_strType;
        string m_strName;

        int m_iID;

        LightSource m_lightSource;

        /// <summary>
        /// Defines the target position over time.
        /// </summary>
        private Path<Vector3> m_translationPath;

        /// <summary>
        /// Defines target direction over time.
        /// </summary>
        private Path<Vector3> m_directionPath;

        /// <summary>
        /// Incremented and used to evaluate the translation path
        /// </summary>
        private double pathTimeTranslation;

        /// <summary>
        /// Incremented and used to evaluate the direction path
        /// </summary>
        private double pathTimeDirection;
        #endregion

        #region Properties
        
        /// <summary>
        /// Gets all light properties.
        /// </summary>
        public LightSource Source { get { return m_lightSource; } }

        public BoundingBox BoundingBox { get { return m_boundingBox; } }

        public Vector3 Position
        {
            get { return m_position; }
            set 
            { 
                m_position = value;
                m_lightSource.Position = value;
                m_boundingBox = new BoundingBox(m_position - Vector3.One * 0.5f, m_position + Vector3.One * 0.5f);
            }
        }

        public Quaternion Orientation
        {
            get { return m_rotation; }
            set 
            { 
                m_rotation = value;
                m_lightSource.Direction = Vector3.TransformNormal(Vector3.Forward/*m_lightSource.Direction*/, Matrix.CreateFromQuaternion(m_rotation));
            }
        }

        new public Vector3 Scale
        {
            get { return new Vector3(m_lightSource.Attenuation0, m_lightSource.Attenuation1, m_lightSource.Attenuation2); }
            set { m_lightSource.Attenuation0 = value.X; m_lightSource.Attenuation1 = value.Y; m_lightSource.Attenuation2 = value.Z; }
        }

        new public string Name
        {
            get { return m_strName; }
            set { m_strName = value; }
        }

        public string Type
        {
            get { return m_strType; }
            set { m_strType = value; }
        }

        public int ID
        {
            get { return m_iID; }
        }

        public Matrix ControllerMatrix
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public bool HasController
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
        #endregion

        #region Constructor

        /// <summary>
        /// Creates a light object for scene.
        /// </summary>
        public LightObject(Vector3 direction)
            : this(LightType.Directional, new Vector3(), direction, 100f, Color.White, Color.White)
        {
        }

        /// <summary>
        /// Creates a light object for scene.
        /// </summary>
        public LightObject(LightType type, Vector3 position, Vector3 directon, float range, Color colorDiffuse, Color colorSpecular) : base()
        {
            // Create a directional light source
            m_lightSource = new LightSource();
            m_lightSource.Direction = directon; 
            m_lightSource.Diffuse = colorDiffuse.ToVector4();
            m_lightSource.Specular = colorSpecular.ToVector4();
            m_lightSource.Type = type;

            m_strName = "";
            m_strType = "Light";

            switch (type)
            {
                case LightType.Directional:
                    m_lightSource.Falloff = 1;
                    m_lightSource.Attenuation0 = 1.0f;
                    m_lightSource.Attenuation1 = 0.1f;
                    m_lightSource.Attenuation2 = 0.0f;                    

                    Name = "DirectionalLight" + m_iID.ToString();
                    break;
                case LightType.Point:
                    Name = "PointLight" + m_iID.ToString();
                    break;                
                case LightType.SpotLight:
                    m_lightSource.Falloff = 1;
                    m_lightSource.Attenuation0 = 1.0f;
                    m_lightSource.Attenuation1 = 0.0f;
                    m_lightSource.Attenuation2 = 0.00f;

                    Name = "SpotLight" + m_iID.ToString();
                    break;
            }

            m_lightSource.Range = range;

            m_iID = Core.GetNextNodeID();
                        
            Position = position;
            m_lightSource.Position = position;

            Vector3 angles = Helpers.AngleTo(position, position + directon);
            Matrix rotation = Matrix.CreateRotationX(angles.X) * Matrix.CreateRotationY(angles.Y) * Matrix.CreateRotationZ(angles.Z);
            m_rotation = Quaternion.CreateFromRotationMatrix(rotation);

            m_boundingBox = new BoundingBox(position - Vector3.One * 0.5f, position + Vector3.One * 0.5f);
        }
        #endregion
    }


    /// <summary>
    /// Creates a directional light using the generic light object class.
    /// </summary>
    public class DirectionalLightObject : LightObject
    {
        /// <summary>
        /// Creates a directional light using the generic light object class.
        /// </summary>
        /// <param name="direction">Defines the light direction.</param>
        /// <param name="intensity">Defines the light intensity.</param>
        /// <param name="diffuseColor">Defines the diffuse color of the light.</param>
        /// <param name="specularColor">Defines the specular</param>
        public DirectionalLightObject(Vector3 direction, float intensity, Color diffuseColor, Color specularColor) :
            base(LightType.Directional, Vector3.Zero, direction, intensity, diffuseColor, specularColor)
        {
        }
    }

    /// <summary>
    /// Creates a spot light using the generic light object class.
    /// </summary>
    public class SpotLightObject : LightObject
    {
        /// <summary>
        /// Creates a spot light using the generic light object class.
        /// </summary>
        /// <param name="position">Defines the light position.</param>
        /// <param name="direction">Defines the light direction.</param>
        /// <param name="intensity">Defines the light intensity.</param>
        /// <param name="diffuseColor">Defines the diffuse color of the light.</param>
        /// <param name="specularColor">Defines the specular</param>
        public SpotLightObject(Vector3 position, Vector3 direction, float intensity, Color diffuseColor, Color specularColor) :
            base(LightType.SpotLight, position, direction, intensity, diffuseColor, specularColor)
        {
        }
    }

    /// <summary>
    /// Creates a point light using the generic light object class.
    /// </summary>
    public class PointLightObject : LightObject
    {
        /// <summary>
        /// Creates a point light using the generic light object class.
        /// </summary>
        /// <param name="position">Defines the light position.</param>
        /// <param name="intensity">Defines the light radius.</param>
        /// <param name="diffuseColor">Defines the diffuse color of the light.</param>
        /// <param name="specularColor">Defines the specular</param>
        public PointLightObject(Vector3 position, float intensity, Color diffuseColor, Color specularColor) :
            base(LightType.Point, position, Vector3.Zero, intensity, diffuseColor, specularColor)
        {
        }
    }
}
